package com.happy.unitconvert.service.impl;

import com.happy.unitconvert.common.exception.BusinessException;
import com.happy.unitconvert.config.properties.AppProperties;
import com.happy.unitconvert.model.dto.ExchangeRateDataWrapper;
import com.happy.unitconvert.service.ExchangeRateApiService;
import com.happy.unitconvert.service.ExchangeRateCacheService;
import com.happy.unitconvert.service.ExchangeRateService;
import com.happy.unitconvert.service.ExchangeRateServiceExtended;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 汇率服务实现
 * 整合API服务和缓存服务，提供完整的汇率功能
 *
 * @author Happy
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExchangeRateServiceImpl implements ExchangeRateService, ExchangeRateServiceExtended {

  private final ExchangeRateApiService exchangeRateApiService;
  private final ExchangeRateCacheService exchangeRateCacheService;
  private final AppProperties appProperties;

  // 默认计算精度
  private static final int DEFAULT_SCALE = 10;

  @Override
  public Mono<Map<String, BigDecimal>> getExchangeRates(String baseCurrency) {
    log.info("获取汇率数据，基础货币: {}", baseCurrency);

    final String finalBaseCurrency = baseCurrency.toUpperCase();

    // 如果启用缓存，先检查缓存
    if (appProperties.getExchangeRate().isCacheEnabled()) {
      return exchangeRateCacheService.getCachedExchangeRates(finalBaseCurrency)
          .switchIfEmpty(fetchAndCacheRates(finalBaseCurrency))
          .doOnNext(rates -> log.info("返回汇率数据，基础货币: {}，包含{}种货币",
              finalBaseCurrency, rates.size()));
    } else {
      // 不使用缓存，直接从API获取
      return fetchRatesFromApi(finalBaseCurrency);
    }
  }

  @Override
  public Mono<BigDecimal> getExchangeRate(String fromCurrency, String toCurrency) {
    log.info("获取特定货币对汇率，从{}到{}", fromCurrency, toCurrency);

    final String finalFromCurrency = fromCurrency.toUpperCase();
    final String finalToCurrency = toCurrency.toUpperCase();

    // 相同货币，汇率为1
    if (finalFromCurrency.equals(finalToCurrency)) {
      return Mono.just(BigDecimal.ONE);
    }

    // 如果启用缓存，先检查缓存
    if (appProperties.getExchangeRate().isCacheEnabled()) {
      return exchangeRateCacheService.getCachedExchangeRate(finalFromCurrency, finalToCurrency)
          .switchIfEmpty(fetchRateFromApiAndCache(finalFromCurrency, finalToCurrency))
          .doOnNext(rate -> log.info("返回汇率，从{}到{}，汇率: {}", finalFromCurrency, finalToCurrency, rate));
    } else {
      // 不使用缓存，直接从API获取
      return fetchRateFromApi(finalFromCurrency, finalToCurrency);
    }
  }

  @Override
  public Mono<BigDecimal> convertCurrency(BigDecimal amount, String fromCurrency, String toCurrency) {
    log.info("执行货币转换，金额: {}，从{}到{}", amount, fromCurrency, toCurrency);

    if (amount == null || amount.compareTo(BigDecimal.ZERO) < 0) {
      return Mono.error(new BusinessException("转换金额必须为正数"));
    }

    return getExchangeRate(fromCurrency, toCurrency)
        .map(rate -> amount.multiply(rate).setScale(DEFAULT_SCALE, RoundingMode.HALF_UP))
        .doOnNext(result -> log.info("货币转换结果，原金额: {} {}，转换后: {} {}",
            amount, fromCurrency, result, toCurrency));
  }

  @Override
  public Mono<Map<String, BigDecimal>> convertCurrencyBatch(BigDecimal amount, String fromCurrency,
      List<String> toCurrencies) {
    log.info("执行批量货币转换，金额: {}，从{}到{}种货币", amount, fromCurrency, toCurrencies.size());

    if (amount == null || amount.compareTo(BigDecimal.ZERO) < 0) {
      return Mono.error(new BusinessException("转换金额必须为正数"));
    }

    if (toCurrencies == null || toCurrencies.isEmpty()) {
      return Mono.just(new HashMap<>());
    }

    return getExchangeRates(fromCurrency)
        .map(rates -> {
          Map<String, BigDecimal> results = new HashMap<>();

          for (String toCurrency : toCurrencies) {
            String upperToCurrency = toCurrency.toUpperCase();
            BigDecimal rate = rates.get(upperToCurrency);

            if (rate != null) {
              BigDecimal convertedAmount = amount.multiply(rate)
                  .setScale(DEFAULT_SCALE, RoundingMode.HALF_UP);
              results.put(upperToCurrency, convertedAmount);
            } else {
              log.warn("未找到汇率，从{}到{}", fromCurrency, toCurrency);
            }
          }

          return results;
        })
        .doOnNext(results -> log.info("批量货币转换完成，转换了{}种货币", results.size()));
  }

  @Override
  public Mono<List<String>> getSupportedCurrencies() {
    log.info("获取支持的货币代码列表");

    return exchangeRateApiService.fetchSupportedCurrencies()
        .doOnNext(currencies -> log.info("返回{}种支持的货币", currencies.size()));
  }

  @Override
  public Mono<Void> refreshCache(String baseCurrency) {
    log.info("刷新汇率缓存，基础货币: {}", baseCurrency);

    if (baseCurrency == null) {
      // 刷新所有缓存
      return exchangeRateCacheService.clearCache(null)
          .doOnSuccess(v -> log.info("已清除所有汇率缓存"));
    } else {
      // 刷新指定货币的缓存
      return exchangeRateCacheService.clearCache(baseCurrency)
          .then(fetchAndCacheRates(baseCurrency))
          .then()
          .doOnSuccess(v -> log.info("已刷新汇率缓存，基础货币: {}", baseCurrency));
    }
  }

  @Override
  public Mono<Boolean> isServiceAvailable() {
    log.info("检查汇率服务可用性");

    return exchangeRateApiService.checkApiHealth()
        .doOnNext(available -> log.info("汇率服务可用性: {}", available ? "可用" : "不可用"))
        .onErrorReturn(false);
  }

  /**
   * 从API获取汇率并缓存
   */
  private Mono<Map<String, BigDecimal>> fetchAndCacheRates(String baseCurrency) {
    return fetchRatesFromApi(baseCurrency)
        .flatMap(rates -> {
          // 缓存汇率数据
          return exchangeRateCacheService.cacheExchangeRates(baseCurrency, rates)
              .then(Mono.just(rates));
        })
        .doOnError(error -> log.error("获取并缓存汇率失败，基础货币: {}，错误: {}",
            baseCurrency, error.getMessage()));
  }

  /**
   * 从API获取汇率数据
   */
  private Mono<Map<String, BigDecimal>> fetchRatesFromApi(String baseCurrency) {
    return exchangeRateApiService.fetchLatestRates(baseCurrency)
        .map(response -> {
          if (!response.isSuccess()) {
            throw new BusinessException("API返回错误: " + response.getErrorInfo());
          }
          return response.getRates();
        })
        .doOnNext(rates -> log.debug("从API获取汇率数据，基础货币: {}，包含{}种货币",
            baseCurrency, rates.size()));
  }

  /**
   * 从API获取特定汇率并缓存
   */
  private Mono<BigDecimal> fetchRateFromApiAndCache(String fromCurrency, String toCurrency) {
    return fetchAndCacheRates(fromCurrency)
        .map(rates -> rates.get(toCurrency))
        .filter(rate -> rate != null)
        .switchIfEmpty(Mono.error(new BusinessException(
            String.format("未找到汇率，从%s到%s", fromCurrency, toCurrency))));
  }

  /**
   * 从API获取特定汇率
   */
  private Mono<BigDecimal> fetchRateFromApi(String fromCurrency, String toCurrency) {
    return fetchRatesFromApi(fromCurrency)
        .map(rates -> rates.get(toCurrency))
        .filter(rate -> rate != null)
        .switchIfEmpty(Mono.error(new BusinessException(
            String.format("未找到汇率，从%s到%s", fromCurrency, toCurrency))));
  }

  // ======== ExchangeRateServiceExtended 接口实现 ========

  @Override
  public Mono<ExchangeRateDataWrapper<Map<String, BigDecimal>>> getExchangeRatesWithSource(String baseCurrency,
      boolean isForceUpdate) {
    log.info("获取汇率数据（包含来源信息），基础货币: {}，强制更新: {}", baseCurrency, isForceUpdate);

    final String finalBaseCurrency = baseCurrency.toUpperCase();

    // 如果强制更新，直接从API获取并缓存
    if (isForceUpdate) {
      return fetchAndCacheRates(finalBaseCurrency)
          .map(rates -> ExchangeRateDataWrapper.ofRates(rates, false)) // 来自API
          .doOnNext(wrapper -> log.info("强制更新汇率数据，基础货币: {}，包含{}种货币",
              finalBaseCurrency, wrapper.getList().size()));
    }

    // 如果启用缓存，先检查缓存
    if (appProperties.getExchangeRate().isCacheEnabled()) {
      return exchangeRateCacheService.getCachedExchangeRates(finalBaseCurrency)
          .map(rates -> ExchangeRateDataWrapper.ofRates(rates, true)) // 来自缓存
          .switchIfEmpty(fetchAndCacheRates(finalBaseCurrency)
              .map(rates -> ExchangeRateDataWrapper.ofRates(rates, false))) // 来自API
          .doOnNext(wrapper -> log.info("返回汇率数据，基础货币: {}，包含{}种货币，数据来源: {}",
              finalBaseCurrency, wrapper.getList().size(), wrapper.isFromCache() ? "缓存" : "API"));
    } else {
      // 不使用缓存，直接从API获取
      return fetchRatesFromApi(finalBaseCurrency)
          .map(rates -> ExchangeRateDataWrapper.ofRates(rates, false));
    }
  }

}
